/*
//
//                  INTEL CORPORATION PROPRIETARY INFORMATION
//     This software is supplied under the terms of a license agreement or
//     nondisclosure agreement with Intel Corporation and may not be copied
//     or disclosed except in accordance with the terms of that agreement.
//          Copyright(c) 2004-2007 Intel Corporation. All Rights Reserved.
//
//     Intel Integrated Performance Primitives AAC Encode Sample for Windows*
//
//  By downloading and installing this sample, you hereby agree that the
//  accompanying Materials are being provided to you under the terms and
//  conditions of the End User License Agreement for the Intel Integrated
//  Performance Primitives product previously accepted by you. Please refer
//  to the file ippEULA.rtf or ippEULA.txt located in the root directory of your Intel IPP
//  product installation for more information.
//
//  MPEG-4 and AAC are international standards promoted by ISO, IEC, ITU, ETSI
//  and other organizations. Implementations of these standards, or the standard
//  enabled platforms may require licenses from various entities, including
//  Intel Corporation.
//
*/

#include "umc_defs.h"

#if defined (UMC_ENABLE_AAC_INT_AUDIO_ENCODER)

#include <math.h>
#include <stdio.h>
#include "aac_enc_filterbank_int.h"
#include "ipps.h"
#include "ippac.h"
#include "aac_enc_wnd_tables_int.h"

/****************************************************************************/

AACStatus InitFilterbank_enc(sFilterbankBlock* pBlock,
                             Ipp8u* mem,
                             Ipp32s *sizeAll)
{
  Ipp32s sizeInit = 0;
  Ipp32s sizeWork = 0;
  Ipp32s sizeSpecFwdLong = 0;
  Ipp32s sizeSpecFwdShort = 0;
  Ipp32s sizeInitTmp = 0;
  Ipp32s sizeWorkTmp = 0;
  Ipp8u  *ptrFwdShort, *ptrWork, *ptrInit;

  if (ippsMDCTFwdGetSize_16s(N_LONG, &sizeSpecFwdLong,
                             &sizeInitTmp, &sizeWorkTmp) != ippStsOk) {
    return AAC_ALLOC;
  }

  if (sizeInit < sizeInitTmp) sizeInit = sizeInitTmp;
  if (sizeWork < sizeWorkTmp) sizeWork = sizeWorkTmp;

  if (ippsMDCTFwdGetSize_16s(N_SHORT, &sizeSpecFwdShort,
                             &sizeInitTmp, &sizeWorkTmp) != ippStsOk) {
    return AAC_ALLOC;
  }

  if (sizeInit < sizeInitTmp) sizeInit = sizeInitTmp;
  if (sizeWork < sizeWorkTmp) sizeWork = sizeWorkTmp;

  *sizeAll = sizeSpecFwdLong + sizeSpecFwdShort + sizeWork + sizeInit;

  if (pBlock) {
    ippsZero_8u((Ipp8u*)pBlock, sizeof(sFilterbankBlock));

    ptrFwdShort = mem + sizeSpecFwdLong;
    ptrWork = ptrFwdShort + sizeSpecFwdShort;
    ptrInit = ptrWork + sizeWork;

    if (ippsMDCTFwdInit_16s(&pBlock->p_mdct_fwd_long, N_LONG,
                            mem, ptrInit) != ippStsOk)
      return AAC_ALLOC;

    if (ippsMDCTFwdInit_16s(&pBlock->p_mdct_fwd_short, N_SHORT,
                            ptrFwdShort, ptrInit) != ippStsOk)
      return AAC_ALLOC;

    pBlock->p_buffer_fwd = ptrWork;

    pBlock->sin_short_wnd_table = SIN_enc_short;
    pBlock->sin_long_wnd_table = SIN_enc_long;
    pBlock->KBD_short_wnd_table = KBD_enc_short;
    pBlock->KBD_long_wnd_table = KBD_enc_long;
  }

  return AAC_OK;
}

/****************************************************************************/

void FreeFilterbank_enc(sFilterbankBlock* pBlock)
{
  if (pBlock->p_mdct_fwd_long)
      ippsMDCTFwdFree_16s(pBlock->p_mdct_fwd_long);
  if (pBlock->p_mdct_fwd_short)
      ippsMDCTFwdFree_16s(pBlock->p_mdct_fwd_short);

  if (pBlock->p_buffer_fwd)
    ippsFree(pBlock->p_buffer_fwd);
}

/****************************************************************************/

void Filterbank_enc(sFilterbankBlock* p_data,
                    Ipp16s* p_in_samples_1st_part,
                    Ipp16s* p_in_samples_2nd_part,
                    Ipp32s window_sequence,
                    Ipp32s window_shape,
                    Ipp32s prev_window_shape,
                    Ipp16s* p_out_spectrum,
                    Ipp32s* mdct_scaleFactor)
{
  Ipp16s  mdct_in[N_LONG];
  Ipp16s  abs_mdct_in[N_LONG];
  Ipp16s  *window_table_long, *prev_window_table_long;
  Ipp16s  *window_table_short, *prev_window_table_short;
  Ipp32s  scaleFactor;
  Ipp32s  i;

  if (0 == window_shape) {
    window_table_long  = p_data->sin_long_wnd_table;
    window_table_short = p_data->sin_short_wnd_table;
  } else {
      window_table_long  = p_data->KBD_long_wnd_table;
      window_table_short = p_data->KBD_short_wnd_table;
  }

  if (0 == prev_window_shape) {
      prev_window_table_long  = p_data->sin_long_wnd_table;
      prev_window_table_short = p_data->sin_short_wnd_table;
  } else {
      prev_window_table_long  = p_data->KBD_long_wnd_table;
      prev_window_table_short = p_data->KBD_short_wnd_table;
  }

  switch(window_sequence)
  {
  case ONLY_LONG_SEQUENCE:
    ippsMul_16s_Sfs(p_in_samples_1st_part, prev_window_table_long,
                    mdct_in, N_LONG/2, 15);

    ippsMul_16s_Sfs(p_in_samples_2nd_part, &window_table_long[N_LONG/2],
                    &mdct_in[N_LONG/2], N_LONG/2, 15);
    break;
  case LONG_START_SEQUENCE:
    ippsMul_16s_Sfs(p_in_samples_1st_part, prev_window_table_long,
                    mdct_in, N_LONG/2, 15);

    ippsCopy_16s(p_in_samples_2nd_part, &mdct_in[1024], 1472-1024);

    ippsMul_16s_Sfs(&p_in_samples_2nd_part[1472-1024],
                    &window_table_short[N_SHORT/2],
                    &mdct_in[1472], 1600-1472, 15);

    ippsZero_8u((Ipp8u *)&mdct_in[1600],sizeof(Ipp16s)*(2048-1600));
    break;
  case LONG_STOP_SEQUENCE:
    ippsZero_8u((Ipp8u *)mdct_in, sizeof(Ipp16s)*448);

    ippsMul_16s_Sfs(&p_in_samples_1st_part[448], prev_window_table_short,
                    &mdct_in[448], 576-448, 15);

    ippsCopy_16s(&p_in_samples_1st_part[576], &mdct_in[576], 1024-576);

    ippsMul_16s_Sfs(p_in_samples_2nd_part, &window_table_long[N_LONG/2],
                    &mdct_in[N_LONG/2], N_LONG/2, 15);
    break;
  case EIGHT_SHORT_SEQUENCE:

    /// W0
    ippsMul_16s_Sfs(&p_in_samples_1st_part[448],
                    prev_window_table_short, &mdct_in[0], N_SHORT/2, 15);
    ippsMul_16s_Sfs(&p_in_samples_1st_part[448+128],
                    &window_table_short[N_SHORT/2], &mdct_in[N_SHORT/2],
                    N_SHORT/2, 15);
    /// W1
    ippsMul_16s_Sfs(&p_in_samples_1st_part[576],
                    window_table_short, &mdct_in[N_SHORT], N_SHORT, 15);
    /// W2
    ippsMul_16s_Sfs(&p_in_samples_1st_part[704],
                    window_table_short, &mdct_in[2*N_SHORT], N_SHORT, 15);
    /// W3
    ippsMul_16s_Sfs(&p_in_samples_1st_part[832],
                    window_table_short, &mdct_in[3*N_SHORT],
                    (3*N_SHORT)/4, 15);
    ippsMul_16s_Sfs(p_in_samples_2nd_part,
                    &window_table_short[192], &mdct_in[3*N_SHORT+192],
                    N_SHORT/4, 15);

    /// W4
    ippsMul_16s_Sfs(&p_in_samples_1st_part[960],
                    window_table_short, &mdct_in[4*N_SHORT], N_SHORT/4, 15);
    ippsMul_16s_Sfs(p_in_samples_2nd_part,
                    &window_table_short[64], &mdct_in[4*N_SHORT+64],
                    (3*N_SHORT)/4, 15);

    /// W5
    ippsMul_16s_Sfs(&p_in_samples_2nd_part[64],
                    window_table_short, &mdct_in[5*N_SHORT], N_SHORT, 15);
    /// W6
    ippsMul_16s_Sfs(&p_in_samples_2nd_part[64+1*128],
                    window_table_short, &mdct_in[6*N_SHORT], N_SHORT, 15);
    /// W7
    ippsMul_16s_Sfs(&p_in_samples_2nd_part[64+2*128],
                    window_table_short, &mdct_in[7*N_SHORT], N_SHORT, 15);
    break;
  default:
    break;
  }

  ippsAbs_16s(mdct_in, abs_mdct_in, N_LONG);

  if (window_sequence != EIGHT_SHORT_SEQUENCE) {
    Ipp32s sum;

    ippsSum_16s32s_Sfs(abs_mdct_in, N_LONG, &sum, 0);

    scaleFactor = 1;
    if (sum != 0) {
      if (sum > 32767) {
        while (sum > 32767) {
          sum >>= 1;
          scaleFactor++;
        }
      } else {
        while (sum < 16384) {
          sum *= 2;
          scaleFactor--;
        }
      }
    }

    ippsMDCTFwd_16s_Sfs(mdct_in, p_out_spectrum, p_data->p_mdct_fwd_long,
                        scaleFactor, p_data->p_buffer_fwd);
  } else {
    Ipp32s sum;
    Ipp32s tmp_scaleFactor;

    scaleFactor = -100;

    for (i = 0; i < 8; i ++) {
      ippsSum_16s32s_Sfs(abs_mdct_in + N_SHORT*i, N_SHORT, &sum, 0);
      tmp_scaleFactor = 1;
      if (sum != 0) {
        if (sum > 32767) {
          while (sum > 32767) {
            sum >>= 1;
            tmp_scaleFactor++;
          }
        } else {
          while (sum < 16384) {
            sum *= 2;
            tmp_scaleFactor--;
          }
        }
      }

      if (tmp_scaleFactor > scaleFactor)
        scaleFactor = tmp_scaleFactor;
    }

    for (i = 0; i < 8; i ++) {
      ippsMDCTFwd_16s_Sfs(&mdct_in[N_SHORT*i],
                          p_out_spectrum+i*(N_SHORT/2),
                          p_data->p_mdct_fwd_short,
                          scaleFactor, p_data->p_buffer_fwd);
    }
  }

  mdct_scaleFactor[0] = scaleFactor;
}

#endif //UMC_ENABLE_AAC_INT_AUDIO_ENCODER

